package com.wrupple.muba.widget.client.widgets.panels.data;

import java.util.List;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.view.client.CellPreviewEvent;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.Range;
import com.google.gwt.view.client.RangeChangeEvent;
import com.google.gwt.view.client.RangeChangeEvent.Handler;
import com.google.gwt.view.client.RowCountChangeEvent;
import com.google.gwt.view.client.SelectionModel;
import com.wrupple.muba.util.client.layout.IndexedLayoutDelegate;
import com.wrupple.muba.widget.client.widgets.panels.PanelWithLayoutPositioner;

public class LayoutDataPanel<T> extends PanelWithLayoutPositioner implements HasData<T> {
	
	public interface DataWidgetFactory<T>{

		IsWidget getWidget(T element);

	}
	
	private class AddToSelection implements ClickHandler {

		private T object;

		public AddToSelection(T object) {
			super();
			this.object = object;
		}

		@Override
		public void onClick(ClickEvent event) {
			if(selectionModel!=null){
				selectionModel.setSelected(object, !selectionModel.isSelected(object));
			}
		}
		
	}
	
	protected LayoutDataPanelDelegate<T> delegate;
	
	private DataWidgetFactory<T> factory;
	private SelectionModel<? super T> selectionModel;

	public LayoutDataPanel( DataWidgetFactory<T> factory,IndexedLayoutDelegate indexedLayoutDelegate) {
		super(indexedLayoutDelegate);
		this.factory=factory;
		delegate = new LayoutDataPanelDelegate<T>(this);
		
	}

	@Override
	public void setRowData(int start, List<? extends T> values) {
		forceLayout();
		//this in turn calls render on this object
		delegate.setRowData(start,values);
		animate(500);
	}

	@Override
	public void setSelectionModel(SelectionModel<? super T> selectionModel) {
		this.selectionModel=selectionModel;
	}
	
	@Override
	public SelectionModel<? super T> getSelectionModel() {
		return selectionModel;
	}
	
	
	protected void render(int start, List<? extends T> values){
		T element;
		IsWidget w;
		for(int i = start ; i< values.size(); i++){
			element = values.get(i);
			
			w = factory.getWidget(element);
			w.asWidget().addHandler(new AddToSelection(element), ClickEvent.getType());
			super.positionElement(w,i);
		}
	}


	@Override
	public void setVisibleRangeAndClearData(Range range, boolean forceRangeChangeEvent) {
		delegate.setVisibleRange(range.getStart(),range.getLength());
		if(forceRangeChangeEvent){
			fireRangeChangeEvent(range);
		}
	}

	@Override
	public void setRowCount(int count) {
		setRowCount(count, true);
	}
	
	@Override
	public int getRowCount() {
		return delegate.getTotalElementsCount();
	}
	@Override
	public boolean isRowCountExact() {
		return true;
	}
	@Override
	public void setRowCount(int count, boolean isExact) {
		delegate.setRowCount(count,isExact);
	}
	
	@Override
	public HandlerRegistration addCellPreviewHandler(com.google.gwt.view.client.CellPreviewEvent.Handler<T> handler) {
		return addHandler(handler, CellPreviewEvent.getType());
	}
	
	@Override
	public HandlerRegistration addRangeChangeHandler(Handler handler) {
		return addHandler(handler, RangeChangeEvent.getType());
	}

	@Override
	public HandlerRegistration addRowCountChangeHandler(com.google.gwt.view.client.RowCountChangeEvent.Handler handler) {
		return addHandler(handler, RowCountChangeEvent.getType());
	}
	
	@Override
	public Range getVisibleRange() {
		return delegate.getVisibleRange();
	}


	@Override
	public void setVisibleRange(int start, int length) {
		if(delegate.setVisibleRange(start,length)){
			fireRangeChangeEvent(new Range(start,length));
		}
	}

	@Override
	public void setVisibleRange(Range range) {
		setVisibleRange(range.getStart(), range.getLength());
	}

	@Override
	public T getVisibleItem(int indexOnPage) {
		return delegate.getVisibleItem(indexOnPage);
	}

	@Override
	public int getVisibleItemCount() {
		return delegate.getVisibleItemCount();
	}

	@Override
	public List<T> getVisibleItems() {
		return delegate.getVisibleItems();
	}
	private void fireRangeChangeEvent(Range range) {
		RangeChangeEvent.fire(this, range);
	}

}
